package 尚硅谷多线程1;
/*
* 例子：创建三个窗口卖票，总票数为100张，使用实现Runnable接口的方式
* 1.问题一：买票的过程中，出现了重票，错票-->出现了线程安全的问题
* 2.问题出现的原因：当某个线程操作车票的过程中，尚未操作完成时，其他线程参与进来，也操作车票
* 3.如何解决：当一个线程在操作ticket的时候，其他线程不能参与进来，直到线程a操作完ticket时，
*            其他线程才可以开始操作ticket；这种情况计时线程a出现了阻塞，也不能改变
* 4.在Java中，我们通过同步机制，来解决线程的安全问题
*
* 方式一： 同步代码块
* synchronized(同步监视器){
*       //需要被同步的代码
*        说明：1.操作共享数据的代码，即为需要被同步的代码)
*             2.共享数据：读个线程共同操作阿德变量。比如：ticket就是共享数据)
*             3. 同步监视器，俗称"锁"。任何一个类的对象，都可以成为锁
*                要求：多个线程必须共用同一把锁。
*                补充在实现Runnable接口创建多线程的方式中，我们可以考虑使用this充当同步监视器
*  5.同步的方式，解决了线程的安全问题。---好处
*             局限性--操作同步代码时，只能有一个线程参与，其他线程等待，相当于是一个线程执行，效率低
*
* }
* 方式二：同步方法
*   如果操作共享数据的代码完整的声明在一个方法中，我们不妨将此方法声明同步的，
*  关于同步方法的总结：
* 1. 同步方法仍然涉及到同步监视器，只是不需要我们显示声明。
* 2. 非静态的同步方法，同步监视器是： this
* 3. 静态的同步方法，同步监视器是： 当前类本身
* */

class Window2 implements Runnable {

private int ticket=100;
    @Override
    public void run() {
        while(true){
            //同步代码synchronized(锁){同步代码}
            synchronized(this) {//this指向的是Window2的唯一对象
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (ticket > 0) {
                    System.out.println(Thread.currentThread().getName() + "卖票 票号" + ticket);
                    --ticket;
                } else break;
            }
        }
    }
}
public class RunnableTest2 {
    public static void main(String[] args) {
        Window2 w2 = new Window2();

        Thread thread1=new Thread(w2);
        Thread thread2=new Thread(w2);
        Thread thread3=new Thread(w2);
        thread1.setName("线程一");
        thread2.setName("线程二");
        thread3.setName("线程三");
        thread1.start();
        thread2.start();
        thread3.start();


    }
}
